#pragma once

#include "compi/tag.h"

#include <memory>
#include <mpi.h>
#include <mutex>
#include <unordered_map>

namespace compi
{

/**
 * 资源管理器
 * 负责管理每个MPI communicator的资源单例，包括TagAllocator
 * 与Context紧密集成，确保资源的正确生命周期管理
 */
class ResourceManager
{
public:
    /**
     * 获取指定communicator的TagAllocator单例
     * 使用Context的communicator管理来确保真实单例
     * @param comm MPI communicator
     * @return TagAllocator的引用
     * @throws std::runtime_error 如果无法创建或获取TagAllocator
     */
    static MessageTagAllocator & get_tag_allocator(MPI_Comm comm);

    /**
     * 销毁指定communicator的TagAllocator
     * 当communicator被释放时调用
     * @param comm MPI communicator
     */
    static void destroy_tag_allocator(MPI_Comm comm);

    /**
     * 清理所有资源
     * 通常在程序退出时调用
     */
    static void cleanup_all();

    /**
     * 获取资源统计信息
     */
    struct ResourceStats
    {
        int active_allocators;    // 活跃的TagAllocator数量
        int total_namespaces;     // 总命名空间数量
        int total_allocated_tags; // 总已分配标签数量
    };
    static ResourceStats get_stats();

private:
    // 禁止实例化
    ResourceManager() = delete;
    ~ResourceManager() = delete;
    ResourceManager(const ResourceManager &) = delete;
    ResourceManager & operator=(const ResourceManager &) = delete;

    /**
     * 自定义删除器，用于处理MessageTagAllocator的私有析构函数
     */
    struct TagAllocatorDeleter
    {
        void operator()(MessageTagAllocator * ptr) const;
    };

    /**
     * 内部实现结构
     */
    struct ResourceEntry
    {
        std::unique_ptr<MessageTagAllocator, TagAllocatorDeleter> tag_allocator;
        MPI_Comm comm;

        ResourceEntry(MPI_Comm c) : comm(c) {}
    };

    // 使用communicator的哈希值作为键，确保真实单例
    static std::unordered_map<std::size_t, std::unique_ptr<ResourceEntry>> s_resources;
    static std::mutex s_resources_mutex;

    /**
     * 计算MPI_Comm的哈希值
     * 使用MPI_Comm_compare确保正确性
     * @param comm MPI communicator
     * @return 哈希值
     */
    static std::size_t compute_comm_hash(MPI_Comm comm);

    /**
     * 查找现有的资源条目
     * @param comm MPI communicator
     * @return 资源条目指针，如果不存在返回nullptr
     */
    static ResourceEntry * find_resource_entry(MPI_Comm comm);

    /**
     * 创建新的资源条目
     * @param comm MPI communicator
     * @return 新创建的资源条目
     */
    static std::unique_ptr<ResourceEntry> create_resource_entry(MPI_Comm comm);
};

} // namespace compi